<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
      overflow: hidden;
    }
    .g-app {
      margin: 0 auto;
      height: 100%;
      width: 100%;
      max-width: 800px;
      padding: 20px;
      box-sizing: border-box;
      overflow-y: auto;
    }
    .list-item {
      height: 300px;
      width: 100%;
      background-color: #f0f0f0;
      margin-bottom: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20px;
      color: #333;
    }
    .loading {
      text-align: center;
      padding: 20px;
      font-size: 18px;
      color: #666;
    }
  </style>
  <body>
    <div class="g-app">
      <ul id="list">
        <li class="list-item">我是列表内容 1</li>
        <li class="list-item">我是列表内容 2</li>
        <li class="list-item">我是列表内容 3</li>
        <li class="list-item">我是列表内容 4</li>
        <li class="list-item">我是列表内容 5</li>
        <li class="list-item">我是列表内容 6</li>
        <li class="list-item">我是列表内容 7</li>
        <li class="list-item">我是列表内容 8</li>
        <li class="list-item">我是列表内容 9</li>
        <li class="list-item">我是列表内容 10</li>
      </ul>
      <div id="loading" class="loading" style="display: none">加载中...</div>
    </div>
    <script>
      function throttle(fn, limit) {
        // 用于存储定时器的引用，以便可以清除定时器
        let timeout = null;

        // 记录上一次执行函数的时间戳
        let lastScrollTime = Date.now();

        // 返回一个新的函数，这个函数会根据节流逻辑决定是否执行传入的函数 fn
        return function (...args) {
          // 获取当前时间戳
          const now = Date.now();

          // 计算剩余时间，即从上次执行到现在的时间与限制时间的差值
          const remainingTime = limit - (now - lastScrollTime);

          // 如果剩余时间小于等于0，说明已经过了足够的时间，可以执行函数
          if (remainingTime <= 0) {
            // 如果已经有一个定时器在运行，清除它
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }

            // 执行传入的函数 fn，并传递当前的参数
            fn.apply(this, args);

            // 更新上一次执行函数的时间戳为当前时间
            lastScrollTime = now;
          } else {
            // 如果剩余时间大于0，说明还没有到足够的时间，设置一个定时器
            // 清除之前的定时器，避免重复设置
            clearTimeout(timeout);
            // 设置一个新的定时器，在剩余时间后执行函数
            timeout = setTimeout(() => {
              // 执行传入的函数 fn，并传递当前的参数
              fn.apply(this, args);

              // 更新上一次执行函数的时间戳为当前时间
              lastScrollTime = Date.now();
            }, remainingTime);
          }
        };
      }

      // 检查是否滚动到底部
      function checkScroll() {
        const loading = document.getElementById("loading");
        const list = document.getElementById("list");
        const scrollContainer = document.querySelector(".g-app");
        // 容器可视区的高度
        const viewportHight = scrollContainer.clientHeight;
        // 滚动条滚动的距离
        const scrollPosition = scrollContainer.scrollTop;
        // 容器的总高度
        const containerHeight = scrollContainer.scrollHeight;

        // 触底条件
        const bottomPosition = containerHeight - viewportHight - scrollPosition;
        console.log("距离底部的高度", bottomPosition);

        if (bottomPosition <= 100) {
          // 100 是提前加载的阈值
          console.log("滚动到底部，触发加载");
          loading.style.display = "block";
          setTimeout(() => {
            // 模拟加载更多数据
            for (let i = 1; i <= 5; i++) {
              const newItem = document.createElement("li");
              newItem.className = "list-item";
              newItem.textContent = `我是新加载的内容 ${
                list.children.length + i
              }`;
              list.appendChild(newItem);
            }
            loading.style.display = "none";
          }, 1000); // 模拟网络延迟
        }
      }

      // 获取滚动容器
      const scrollContainer = document.querySelector(".g-app");
      // 监听滚动事件
      scrollContainer.addEventListener("scroll", throttle(checkScroll, 500));

      // 获取元素
      const ul = document.getElementById('list');
      ul.addEventListener('click', (e)=> {
        console.log('使用事件委托，减少事件绑定', e.target.innerHTML)
      })

    </script>
  </body>
</html>
